﻿using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using XW.Data;

namespace XW.Utils
{
    /// <summary>
    /// 数据类型转换
    /// </summary>
    public static partial class CommonHelper
    {
        /// <summary>
        /// 转换为int
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="defaultValue">默认值 不输入则为0</param>
        /// <returns></returns>
        public static int ToInt(object? obj)
        {
            return ToInt(obj, 0);
        }

        /// <summary>
        /// 转换为int
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="defaultValue">默认值 不输入则为0</param>
        /// <returns></returns>
        public static int ToInt(object? obj, int defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return Convert.ToInt32(obj.ToString());
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 转换为double
        /// </summary>
        /// <param name="obj">需要转换的值</param>
        /// <param name="defaultValue">默认为0</param>
        /// <returns>双精度数</returns>
        public static double ToDouble(object obj)
        {
            return ToDouble(obj, 0);
        }

        /// <summary>
        /// 转换为double
        /// </summary>
        /// <param name="obj">需要转换的值</param>
        /// <param name="defaultValue">默认为0</param>
        /// <returns>双精度数</returns>
        public static double ToDouble(object obj, double defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return Convert.ToDouble(obj);
            }
            catch
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 转换为float
        /// </summary>
        /// <param name="obj">需要转换的值</param>
        /// <param name="defaultValue">默认为0</param>
        /// <returns>双精度数</returns>
        public static float ToFloat(object obj)
        {
            return ToFloat(obj, 0);
        }

        public static T Dic2Object<T>(IEnumerable<KeyValuePair<string, StringValues>>  kvPairs) where T  : new() { 
            T  t = new T();
            var itemType = typeof(T);
            var _properties = ReflectionHelper.GetProperties(itemType);
            foreach (var kv in kvPairs)
            {
                try
                {  
                    var wasMapped = false;

                    PropertyInfo property = null;
                    var  key = kv.Key.ToLower();
                    if (_properties.TryGetValue(key, out property))
                    {
                        SetPropertyValue( property, t, kv.Value);
                        wasMapped = true;
                    }
                    else
                    {
                        if (key.IndexOf('_') != -1) {
                            key = key.Replace("_", "");
                            if (_properties.TryGetValue(key, out property))
                            {
                                SetPropertyValue(property, t, kv.Value);
                                wasMapped = true;
                            }
                        } 
                    } 
                }
                catch (Exception ex)
                {

                    throw ex;
                }

            }
            return t;
        }
         

        private static void SetPropertyValue( PropertyInfo property, object item, object value)
        {
            try
            {
                if (value == DBNull.Value)
                {
                    if (ReflectionHelper.IsNullable(property))
                        value = null;
                    else
                        value = ReflectionHelper.GetDefault(property.PropertyType);
                }
                else
                {
                    var propertyType = ReflectionHelper.GetPropertyType(property);

                    if (propertyType != typeof(string))
                    {
                        if (propertyType.IsEnum())
                        {
                            //if (field.Type == typeof(string))
                            //    value = Enum.Parse(propertyType, (string)value, true);
                            //else
                                value = Enum.ToObject(propertyType, value);
                        }
                        else if (!ReflectionHelper.IsBasicClrType(propertyType))
                            return;
                        else if (propertyType == typeof(string))
                            value = value.ToString();
                        else if (propertyType == typeof(int))
                            value = CommonHelper.ToInt(value);
                        else if (propertyType == typeof(int?))
                            value = CommonHelper.ToInt32Null(value);
                        else if (propertyType == typeof(long))
                            value = CommonHelper.ToInt64(value);
                        else if (propertyType == typeof(long?))
                            value = CommonHelper.ToInt64Null(value);
                        else
                            value = Convert.ChangeType(value, property.PropertyType);
                    }
                    else
                    {
                        value = value.ToString();
                    }
                }

                property.SetValue(item, value, null);
            }
            catch (Exception exception)
            {
                throw new Exception("类型转换失败: " + property.Name, exception);
            }
        }
        /// <summary>
        /// 转换为double
        /// </summary>
        /// <param name="obj">需要转换的值</param>
        /// <param name="defaultValue">默认为0</param>
        /// <returns>双精度数</returns>
        public static float ToFloat(object obj, float defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return float.Parse(obj.ToString());
            }
            catch
            {
                return defaultValue;
            }
        }

        /// <summary>
        /// 转为Decimal
        /// </summary>
        /// <param name="str">表示数字的字符串</param>
        /// <returns>Decimal</returns>
        public static decimal ToDecimal(object obj)
        {
            return ToDecimal(obj, 0);
        }

        /// <summary>
        /// 转为Decimal
        /// </summary>
        /// <param name="str">表示数字的字符串</param>
        /// <returns>Decimal</returns>
        public static decimal ToDecimal(object obj, decimal defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
				if (obj is StringValues)
				{
					var str = obj.ToString();
					return decimal.Parse(str);
				}
				return Convert.ToDecimal(obj);
            }
            catch
            {
                return defaultValue;
            }
        }


        public static Int64 ToInt64(object? obj)
        {
            return ToInt64(obj, 0);
        }

        public static Int64 ToInt64(object? obj, Int64 defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                if (obj is StringValues)
                {
                    var str = obj.ToString();
					return Int64.Parse(str);
				}
                return Convert.ToInt64(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static Int16 ToInt16(object obj, Int16 defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return Convert.ToInt16(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static Single ToSingle(object obj)
        {
            return ToSingle(obj, 0);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static Single ToSingle(object obj, Single defaultValue)
        {

            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return Convert.ToSingle(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static string ToString(object obj, string defaultValue = "")
        {
            try
            {
                return ((obj == null) || (obj == DBNull.Value)) ? defaultValue : Convert.ToString(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static DateTime ToDateTime(object obj)
        {
            return ToDateTime(obj, DateTime.MinValue);
        }

        public static DateTime ToDateTime(object obj, DateTime defaultValue)
        {

            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return Convert.ToDateTime(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static TimeSpan ToTimeSpan(object obj)
        {
            return ToTimeSpan(obj, TimeSpan.MinValue);
        }

        public static TimeSpan ToTimeSpan(object obj, TimeSpan defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {
                return TimeSpan.Parse(obj.ToString());
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static DateTime? ToDateTimeNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToDateTime(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static byte ToByte(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return byte.MinValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return byte.MinValue;
            }
            try
            {
                return Convert.ToByte(obj);
            }
            catch (Exception)
            {
                return byte.MinValue;
            }
        }

        public static byte[] ToByteArrayNull(object obj)
        {
            return ((obj == null) || (obj == DBNull.Value) || (obj.Equals(""))) ? null : (byte[])obj;
        }

        public static string BoolToString(bool flag)
        {
            return flag ? "1" : "0";
        }

        public static bool StringToBool(string flag)
        {
            return flag == "1";
        }

        public static Guid ToGuid(object obj)
        {
            return ToGuid(obj, Guid.Empty);
        }
        public static Guid? ToGuidNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {

                if (obj is byte[])
                {
                    return new Guid((byte[])obj);
                }
                else
                {
                    var value = obj.ToString();
                    if (value.Length == 24)
                    {
                        return new Guid(Convert.FromBase64String(value));
                    }
                    return new Guid(value);
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Guid ToGuid(object obj, Guid defaultValue)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            try
            {

                if (obj is byte[])
                {
                    return new Guid((byte[])obj);
                }
                else
                {
                    var value = obj.ToString();
                    if (value.Length == 24)
                    {
                        return new Guid(Convert.FromBase64String(value));
                    }
                    return new Guid(value);
                }
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static bool ToBool(object obj)
        {
            return ToBool(obj, false);
        }

        public static bool ToBool(object obj, bool defaultValue)
        {

            if (obj == null || obj == DBNull.Value)
            {
                return defaultValue;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return defaultValue;
            }
            if (obj is string)
            {
                var ipt = obj.ToString().Trim().ToLower();
                if (ipt == "1" || ipt == "true" || ipt == "成功" || ipt == "是" || ipt == "yes")
                {
                    return true;
                }
                else if (ipt == "0" || ipt == "false" || ipt == "失败" || ipt == "否")
                {
                    return false;
                }
            }
            try
            {
                return Convert.ToBoolean(obj);
            }
            catch (Exception)
            {
                return defaultValue;
            }
        }

        public static bool? ToBoolNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToBoolean(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static DateTime? DbNullToDatetimeNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToDateTime(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Int32? ToInt32Null(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToInt32(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Int64? ToInt64Null(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToInt64(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Decimal? ToDecimalNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToDecimal(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static string ToStringNull(object obj)
        {
            if (obj == null || obj == DBNull.Value)
            {
                return null;
            }
            if (obj is string && string.IsNullOrWhiteSpace(obj.ToString()))
            {
                return null;
            }
            try
            {
                return Convert.ToString(obj);
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static T To<T>(this object input)
        {
            T value = default(T);
            try
            {
                object result = default(T);
                if (typeof(T) == typeof(int))
                    result = ToInt(input);
                else if (typeof(T) == typeof(long))
                    result = ToInt64(input);
                else if (typeof(T) == typeof(string))
                    result = ToString(input);
                else if (typeof(T) == typeof(bool))
                    result = ToBool(input);
                else if (typeof(T) == typeof(double))
                    result = System.Convert.ToDouble(input);
                else if (typeof(T) == typeof(DateTime))
                    result = System.Convert.ToDateTime(input);
                else
                    result = input;

                return (T)result;
            }
            catch (Exception)
            {


            }
            return value;
        }

        public static List<int> ToInts(string str, char split = ',')
        {
            if (string.IsNullOrEmpty(str))
            {
                return new List<int>();
            }
            return str.Split(split).ToList().Select(s => s.ToInt()).ToList();
        }

        public static List<T> ToList<T>(string str, char split = ',')
        {
            if (string.IsNullOrEmpty(str))
            {
                return new List<T>();
            }
            return str.Split(split).ToList().Select(s => s.To<T>()).ToList();
        }

        /// <summary>
        ///  改变类型
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="type">The type.</param>
        /// <returns>System.Object.</returns>
        public static object ChangeType(object value, Type type)
        {
            try
            {
                if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
                if (value == null) return null;
                if (type == value.GetType()) return value;
                if (type.IsEnum)
                {
                    if (value is string)
                        return Enum.Parse(type, value as string);
                    else
                        return Enum.ToObject(type, value);
                }
                if (!type.IsInterface && type.IsGenericType)
                {
                    Type innerType = type.GetGenericArguments()[0];
                    object innerValue = ChangeType(value, innerType);
                    return Activator.CreateInstance(type, new object[] { innerValue });
                }
                if (value is string && type == typeof(Guid)) return new Guid(value as string);
                if (value is string && type == typeof(Version)) return new Version(value as string);
                if (!(value is IConvertible)) return value;
                return Convert.ChangeType(value, type);
            }
            catch (Exception ex)
            {
                return Activator.CreateInstance(type);
            }
        }


        public static string GetExceptionMsg(Exception ex, string title = "", int length = 2000)
        {
            string errorMsg = title + (string.IsNullOrEmpty(ex.Message) ? ex.InnerException.Message : ex.Message);
            errorMsg += "\r\nStackTrace:" + ex.StackTrace;
            errorMsg = errorMsg.ToSafeLeft(length);
            return errorMsg;
        }
        /// <summary>
        /// 获得相对路径时用
        /// </summary>
        /// <returns></returns>
        public static string GetRelativePath(string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                return path.Substring(1);
            }
            else
            {
                return null;
            }
        }
        public static byte[] ConvertImage2Byte(string path)
        {
            var filePath = path.TrimStart('/');
            if (path.StartsWith("/upload/"))
            {


                // 如果不存在先下载
                if (!System.IO.File.Exists(filePath))
                {
                    var fileDir = filePath.Substring(0, filePath.LastIndexOf('/'));
                    if (!Directory.Exists(fileDir))
                    {
                        Directory.CreateDirectory(fileDir);
                    }
                    EasyHttp.With("http://degre.cnsanhe.com:8060" + path).GetForFile(filePath);
                }


            }


            if (!System.IO.File.Exists(filePath)) //下载不成功就返回Null
            {
                return null;
            }

            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); //将图片以文件流的形式进行保存
            BinaryReader br = new BinaryReader(fs);
            byte[] imgBytesIn = br.ReadBytes((int)fs.Length); //将流读入到字节数组中
            return imgBytesIn;
        }

        public static byte[] ConvertImage2Byte2(string path, int maxWidth = 1920, int maxHeight = 1080)
        {
            var filePath = path.TrimStart('/');
            if (path.StartsWith("/upload/"))
            {


                // 如果不存在先下载
                if (!System.IO.File.Exists(filePath))
                {
                    var fileDir = filePath.Substring(0, filePath.LastIndexOf('/'));
                    if (!Directory.Exists(fileDir))
                    {
                        Directory.CreateDirectory(fileDir);
                    }
                    EasyHttp.With("http://degre.cnsanhe.com:8060" + path).GetForFile(filePath);
                }


            }


            if (!System.IO.File.Exists(filePath)) //下载不成功就返回Null
            {
                return null;
            }

            byte[] imgBytesIn = ImageHelper.ThumbImg(filePath, maxWidth, maxHeight); //将流读入到字节数组中
            return imgBytesIn;
        }

        public static bool IsPrivateNetwork(string ipv4Address)
        {
//#if DEBUG
//            return false;
//#endif
            // 本机
            if (ipv4Address == "127.0.0.1")
            {
                return true;
            }

            if (IPAddress.TryParse(ipv4Address, out var ip))
            {
                byte[] ipBytes = ip.GetAddressBytes();
                if (ipBytes[0] == 10) return true;
                if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
                if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
            }

            return false;
        }

         
        /// <summary>
        /// 是否为数字
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public static bool IsNumeric(string field)
        {
            field = field.Replace(".", ""); // strip dots
            for (var i = 0; i < field.Length; i++)
            {
                if (!char.IsDigit(field[i]))
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// 格式化工票号
        /// </summary>
        /// <returns></returns>
        public static string FormatWorkNum(int worknum)
        {
            string workNum = worknum.ToString();
            if (workNum.Length < 2)
            {
                return workNum;
            }
            if (workNum.Substring(workNum.Length - 1,1) == "0")
            {
                return workNum[..^1] ;
            }
            return workNum.Substring(0, workNum.Length - 1) + "-" + workNum.Substring(workNum.Length - 1,1);
        }

    }
}